/**
 * mvp-Lite GPU Resource Manager
 * 功能：
 *   - 注册与跟踪所有 GPU 资源
 *   - 限制总内存（按类型分组）
 *   - 使用 LRU 算法回收最久未使用资源
 */
import { ResourceRecord } from './ResourceRecord.js';

export class GpuResourceManager {
  constructor(gl, options = {}) {
    this.gl = gl;
    this.limits = {
      textureBytes: options.textureLimit || 512 * 1024 * 1024,   // 512MB
      bufferBytes: options.bufferLimit || 256 * 1024 * 1024,     // 256MB
      framebufferBytes: options.framebufferLimit || 128 * 1024 * 1024
    };

    this.usage = {
      textureBytes: 0,
      bufferBytes: 0,
      framebufferBytes: 0,
    };

    /** Map<string, {glObject, type, byteSize, lastUsed}> */
    this.resources = new Map();
  }

  /**
   * 注册资源
   * @param {string} key - 唯一键
   * @param {WebGLObject} glObject
   * @param {'texture'|'buffer'|'framebuffer'} type
   * @param {number} byteSize - 估算字节数
   */
  register(key, glObject, type, byteSize) {
    if (this.resources.has(key)) {
      this.markUsed(key);
      return;
    }
    const record = {
      glObject,
      type,
      byteSize,
      lastUsed: performance.now(),
    };
    this.resources.set(key, record);
    this.usage[this._typeKey(type)] += byteSize;
    this._checkLimit(type);
  }

  /**
   * 标记资源被使用
   */
  markUsed(key) {
    const rec = this.resources.get(key);
    if (rec) rec.lastUsed = performance.now();
  }

  /**
   * 删除指定资源
   */
  delete(key) {
    const rec = this.resources.get(key);
    if (!rec) return;
    this._destroy(rec);
    this.resources.delete(key);
  }

  /**
   * 内部销毁资源（真正调用 gl.deleteXxx）
   */
  _destroy(rec) {
    const gl = this.gl;
    switch (rec.type) {
      case 'texture': gl.deleteTexture(rec.glObject); break;
      case 'buffer': gl.deleteBuffer(rec.glObject); break;
      case 'framebuffer': gl.deleteFramebuffer(rec.glObject); break;
    }
    this.usage[this._typeKey(rec.type)] -= rec.byteSize;
  }

  /**
   * 检查内存限制并执行 LRU 回收
   */
  _checkLimit(type) {
    const key = this._typeKey(type);
    const used = this.usage[key];
    const limit = this.limits[key];

    if (used <= limit) return;

    // 执行 LRU 回收
    const over = used - limit;
    let freed = 0;
    const arr = Array.from(this.resources.entries())
      .filter(([k, r]) => r.type === type)
      .sort((a, b) => a[1].lastUsed - b[1].lastUsed); // oldest first

    for (const [key, rec] of arr) {
      this._destroy(rec);
      this.resources.delete(key);
      freed += rec.byteSize;
      if (freed >= over) break;
    }
    console.warn(`[GpuResourceManager] Freed ${Math.round(freed/1024/1024)} MB (${type}) due to memory limit.`);
  }

  /**
   * 帧循环调用：自动回收过久未使用的资源（可选）
   * @param {number} maxAgeMs - 超过该时间未使用的资源将被回收
   */
  collectGarbage(maxAgeMs = 15000) {
    const now = performance.now();
    const arr = Array.from(this.resources.entries());
    for (const [key, rec] of arr) {
      if (now - rec.lastUsed > maxAgeMs) {
        this._destroy(rec);
        this.resources.delete(key);
      }
    }
  }

  /**
   * 获取当前统计信息
   */
  getStats() {
    return {
      ...this.usage,
      totalBytes:
        this.usage.textureBytes +
        this.usage.bufferBytes +
        this.usage.framebufferBytes,
      count: this.resources.size,
    };
  }

  _typeKey(type) {
    if (type === 'texture') return 'textureBytes';
    if (type === 'buffer') return 'bufferBytes';
    return 'framebufferBytes';
  }
}